package com.ezops.poc.validations.validators;

import java.lang.reflect.Field;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ezops.annotation.EzopsDisplayName;
import com.ezops.poc.util.EzopsConfigException;
import com.ezops.poc.validations.result.ValidationResult;

public abstract class AbstractValidator implements IValidators {

	private static final Logger logger = LoggerFactory
			.getLogger(AbstractValidator.class);
	protected List<Integer> assets;
	protected String ezopsDisplayFieldName;
	String fieldName;

	@Override
	public void init(String fieldName, List<Integer> assets, String... values) {
		logger.trace("Initializing validtor instance");
		this.assets = assets;
		init(fieldName, values);
	}

	public abstract void init(String fieldName, String... values);

	@Override
	public ValidationResult validate(Object model) {
		if (applicableForCurrentAsset(model) == false) {
			return ValidationResult.getValidResponse();
		}
		validateRuleField(model);
		return validateModel(model);
	}

	public abstract ValidationResult validateModel(Object model);

	/**
	 * Return true if the current model has the asset type in {@code assets}
	 * 
	 * @param model
	 * @return
	 */
	protected boolean applicableForCurrentAsset(Object model) {
		if (assets == null) {
			// applicable for all assets.
			return true;
		}
		try {
			final Field field = model.getClass().getSuperclass()
					.getDeclaredField("assetId");
			field.setAccessible(true);
			Object value = field.get(model);
			if (assets.contains((Integer) value) == false) {
				logger.debug("This validation is not applicable for current row as the asset class required is "
						+ assets.toString()
						+ " but model has "
						+ value.toString() + ". Skipping the valdation");
				return false;
			}

		} catch (NoSuchFieldException | SecurityException
				| IllegalArgumentException | IllegalAccessException e) {
			logger.error(
					"Error while extracting the asset for the model {} , Reason -{}"
							+ model.toString(), e.getMessage());

		}
		return true;
	}

	/**
	 * Validate the field name, if not valid throw exception.
	 * 
	 * @param model
	 */
	protected void validateRuleField(Object model) {
		if (model == null) {
			throw new IllegalArgumentException("Can't not validate null model");
		}
	
		for (Field field : model.getClass().getDeclaredFields()) {
			if (field.getAnnotation(EzopsDisplayName.class) != null) {
				if (field.getAnnotation(EzopsDisplayName.class).name()
						.equalsIgnoreCase(ezopsDisplayFieldName)) {
					this.fieldName = field.getName();
					break;
				}
			}
		}
		if (fieldName == null) {
			throw new EzopsConfigException("ezopsValidation.xml",
					"Unknown ezops field defined in validation xml. Field name -"
							+ ezopsDisplayFieldName);
		}
	}

}
